package controllers;

import java.util.LinkedList;
import java.util.List;

import models.Action;
import models.Component;
import models.ComponentUser;
import models.Event;
import models.EventType;
import models.Log;
import models.Notification;
import models.Project;
import models.Role;
import models.Task;
import models.TaskUserUser;
import models.User;
import models.UserRoleProject;
import notifiers.Mails;
import play.data.validation.Required;
import play.db.jpa.JPASupport;
import play.libs.Crypto;
import play.libs.Mail;
import play.mvc.Controller;
import play.mvc.With;

/**
 * @author Magued
 * 
 */
@With(Secure.class)
public class Users extends Controller {

	public static boolean changeNotifyStatus(long userId, int status) {

		boolean stat = false;
		if (status == 1) {
			stat = true;
		} else {
			stat = false;
		}
		User temp = User.findById(userId);
		temp.isNotified = stat;
		temp.save();
		return true;
	}

	public static boolean getNotifyStatus(long userId) {
		User temp = User.findById(userId);
		boolean send = temp.isNotified;
		renderJSON(send);
		return true;
	}

	/**
	 * Responds to the request of creating a project either accept or reject,
	 * should be invoked only by system admin
	 * 
	 * @param projectId
	 *            the project id
	 * @param accepted
	 *            whether it is accepted or not
	 * 
	 */
	public static void respondToProjectRequest(long projectId, boolean accepted) {
		if (!Security.checkPermission("Respond to project creation requset",
				null))
			forbidden();
		// Get the project
		Project project = Project.findById(projectId);
		// Get project admin role
		// Get the project admin of this project
		User projectAdmin = UserRoleProject
				.find(
						"select usp.user from UserRoleProject usp where usp.project=? and usp.role.title='Project Admin'",
						project).first();
		String msg = "";
		if (accepted == true) {
			project.status = true;
			EventType defaultType = EventType.find("byType", "default").first();
			Event event = new Event();
			event.type = defaultType;
			event.project = project;
			event.save();
			project.save();
			// Associate the project to a default component
			Component defaultComp = new Component("Default component",
					"Serves as default component for that project", project);
			defaultComp.save();
			msg = "Project " + project.name + " accepted";
			flash.success(msg);

		} else {

			msg = "Project " + project.name + " rejected";
			flash.success(msg);
			project.delete();
		}
		Mails.notify(projectAdmin, "Project creation response", msg,
				accepted ? "/projects/showProject?projectId="
						+ project.getEntityId() : "");
		new Notification((Long) projectAdmin.getEntityId(),
				"Project request response", msg).save();
		new Log((Long) projectAdmin.getEntityId(), projectId, Project.class
				.getName(), msg, projectId, "").save();
		// Return to home page
		Projects.showRequestedProjects();
	}

	/**
	 * Sends an invitation email message to a registered user. The message
	 * contains a link which redirects to an accept redirect page. These links
	 * hold information about the project and role the guest is invited to join.
	 * 
	 * @param to
	 *            the guest's email
	 * @param project
	 *            the project that the guest should join after accepting
	 * @param role
	 *            the role the guest should have after accepting
	 */
	private static void sendInvitation(String to, User user, Project project,
			Role role) {
		UserRoleProject userRoleProject = new UserRoleProject(false, user,
				role, project);
		userRoleProject.save();
		String username = user.userName;
		String encPId = encryptValue(Long.parseLong(project.getEntityId()
				.toString()));
		String encRId = encryptValue(Long.parseLong(role.getEntityId()
				.toString()));
		String encUId = encryptValue(Long.parseLong(user.getEntityId()
				.toString()));
		String link = String
				.format(
						"http://localhost:9000/Users/inviteToProjectEnc?pId=%s&rId=%s&uId=%s",
						encPId, encRId, encUId);
		String message = String
				.format(
						"Dear %s,\nYou have been invited to join the project \"%s\" with the role \"%s\".\nTo accept please click the following link: \n%s",
						username, project.name, role.title, link);
		Mails.notify(user, "Project Invitation", message, link);
	}

	/**
	 * the method that is called when the user clicks on the link sent to him
	 * 
	 * @author ayasa2r
	 * @param projectId
	 * @param roleId
	 * @param userId
	 */
	public static void inviteToProject(@Required long projectId, long roleId,
			long userId) {
		Project project = Project.findById(projectId);
		String projectName = project.name;
		Role role = Role.findById(roleId);
		String roleName = "";
		if (role != null)
			roleName = role.title;
		if (Long.parseLong(session.get("userId")) == userId)
			render(projectId, roleId, userId, projectName, roleName);
		else
			Admin.index();

	}

	/**
	 * takes encrypted parameters and returns their decrypted version
	 * 
	 * @param pId
	 *            project Id
	 * @param rId
	 *            role Id
	 * @param uId
	 *            user invited Id
	 */
	public static void inviteToProjectEnc(@Required String pId, String rId,
			String uId) {
		long projectId = decryptValue(pId);
		long roleId = decryptValue(rId);
		long userId = decryptValue(uId);
		inviteToProject(projectId, roleId, userId);
	}

	/**
	 * encrypts a long to a string value
	 * 
	 * @param someId
	 * @return
	 */

	private static String encryptValue(long someId) {
		return Crypto.encryptAES(someId + "");
	}

	/**
	 * decrypts a string to a long value
	 * 
	 * @param someEncString
	 * @return
	 */
	private static long decryptValue(String someEncString) {
		return Long.parseLong(Crypto.decryptAES(someEncString));
	}

	/**
	 * Responds to the call from the inviteToProject clicked button and
	 * according to the button clicked the status is dependent. If the user
	 * clicks on the Accept button, called with status = true, if clicks on
	 * Reject button, called with status = false.
	 * 
	 * @param u
	 *            the user that is inserted in the UserRoleProject table
	 * @param status
	 *            the status of the invitation
	 * 
	 */
	public static void updateInvitaionStatus(long projectId, long roleId,
			long userId, boolean status) {
		String message = " Andd....";
		Project project = Project.findById(projectId);
		Role role = Role.findById(roleId);
		UserRoleProject u = UserRoleProject.find("byProjectAndRoleAndUser",
				project, role, User.findById(userId)).first();
		if (u != null) {
			if (status) {
				u.status = true;
				u.save();
				if ((Long) u.user.getEntityId() != null
						&& userId == (Long) u.user.getEntityId()) {
					message = u.user.userName
							+ "Thank you for accepting the invitation to join the "
							+ u.project.name + "project. ";
					if (u.role != null)
						message += "You have the role " + u.role.title
								+ ". HAVE A BLAST!";
					else
						message += "HAVE A BLAST!";
				} else
					message = "Please log in.";
			} else {
				u.delete();
				message = "Thank you and good bye :)";
			}
		} else {
			flash.error("you are not allowed to do this action!");
			inviteToProject(projectId, roleId, userId);
		}
		flash.success(message);
		Projects.showProject(projectId);
	}

	/**
	 * Sends an invitation email message to a guest. The message contains a link
	 * which redirects to the accept/reject page. These links hold information
	 * about the project and role the guest is invited to join.
	 * 
	 * @param to
	 *            the guest's email
	 * @param project
	 *            the project that the guest should join after accepting
	 * @param role
	 *            the role the guest should have after accepting
	 */
	private static void sendInvitationToGuest(String to, Project project,
			Role role) {
		/*
		 * UserRoleProject userRoleProject = new UserRoleProject(false, null,
		 * role, project); userRoleProject.save();
		 */
		String username = "Guest";
		long pId = Long.parseLong(project.getEntityId().toString());
		long rId = Long.parseLong(role.getEntityId().toString());
		String encPrjId = encryptValue(pId);// Crypto.encryptAES(project.getEntityId().toString());
		String encRlId = encryptValue(rId);// Crypto.encryptAES(role.getEntityId().toString());
		String link = String
				.format(
						"http://coolscrum.selfip.com/Application/guestInvitation?pId=%s&rId=%s",
						encPrjId, encRlId);
		String message = String
				.format(
						"Dear %s,\nYou have been invited to join the project \"%s\" with the role \"%s\".\nTo accept/reject please click the following link: \n%s",
						username, project.name, role.title, link);
		Mail.send("coolSoft@SMT.com", to, "Project Invitation!", message);
	}

	/**
	 * checks if user is on system, or if user is already a member of the
	 * project given the users email or username, and notifies the user with
	 * invitation in case of a successful invitation, displays an error to user
	 * in case of wrong data entry
	 * 
	 * @author selkasrawy
	 * @param projectId
	 * @param roleSelect
	 * @param userEntry
	 * @param userValue
	 * @param users
	 * @param emails
	 * @param email
	 */
	public static void invitationMessage(long projectId, long selection,
			String userEntry, String userValue, String users, String emails,
			String email) {
		long pId = projectId;
		long rId = selection;
		long uId = Long.parseLong(session.get("userId"));
		Role role = null;
		User user = null;
		Project project = null;
		String msg = "";
		String confirmation = "";
		String sendMessage = "";
		User isMember = null;
		project = Project.findById(pId);

		if (userEntry.equals("email")) {
			isMember = User
					.find("select user from User user where user.email =?",
							userValue).first();
			if (isMember == null) {
				params.flash();
				flash.error("This user is not registered on the system!");
				Projects.selectRoleInProject(pId, false, true);
			} else {
				User u = UserRoleProject
						.find(
								"select urp.user from UserRoleProject urp where urp.project=? and urp.user=?",
								project, isMember).first();

				if (u != null) {
					boolean status = UserRoleProject
							.find(
									"select urp.status from UserRoleProject urp where urp.project=? and urp.user=?",
									project, isMember).first();
					if (status == true) {
						params.flash();
						flash
								.error("This user is already a member of the project");
					} else {
						params.flash();
						flash.error("You already invited this user before");
					}
					Projects.selectRoleInProject(pId, false, true);
				}
			}
		} else {
			isMember = User.find(
					"select user from User user where user.userName=?",
					userValue).first();

			if (isMember == null) {
				params.flash();
				flash.error("This user is not registered on the system! ");
				Projects.selectRoleInProject(pId, false, true);
			} else {
				User u = UserRoleProject
						.find(
								"select urp.user from UserRoleProject urp where urp.project=? and urp.user=?",
								project, isMember).first();

				if (u != null) {
					boolean status = UserRoleProject
							.find(
									"select urp.status from UserRoleProject urp where urp.project=? and urp.user=?",
									project, isMember).first();
					if (status == true) {
						params.flash();
						flash
								.error("This user is already a member of the project");
					} else {
						params.flash();
						flash.error("You already invited this user before");
					}
					Projects.selectRoleInProject(pId, false, true);
				}
			}
		}
		user = User.findById(uId);

		if (rId == 0) {
			role = Role
					.find(
							"select role from Role role where role.title='Project Member'")
					.first();
			confirmation = "Your invitation to " + isMember.userName
					+ " to join " + project.name
					+ " has been sent successfully";
			msg = "User " + user.userName + " has invited " + isMember.userName
					+ " to join the project " + project.name;
			sendMessage = "User " + user.userName
					+ " has invited you to join the project " + project.name;
		} else {
			role = Role.findById(rId);
			if (role == null) {
				params.flash();
				flash.error("This role does not exist");
				Projects.selectRoleInProject(pId, false, true);
			} else {
				confirmation = "Your invitation to " + isMember.userName
						+ " to join " + project.name + " with role "
						+ role.title + " has been sent successfully";
				msg = "User " + user.userName + " has invited "
						+ isMember.userName + " to join the project "
						+ project.name + " as " + role.title;
				sendMessage = "User " + user.userName
						+ " has invited you to join the project "
						+ project.name + " as " + role.title;
			}
		}
		params.flash();
		flash.success(confirmation);
		new Notification(Long.parseLong(isMember.getEntityId().toString()),
				"Project Invitation", sendMessage).save();
		new Log(uId, pId, Project.class.getName(), msg, pId, "").save();
		sendInvitation(isMember.email, isMember, project, role);
		render("Application/index.html");
	}

	/**
	 * sends invitation to guest and displays success or failure of the
	 * invitation sending
	 * 
	 * @author selkasrawy
	 * @param roleSelect
	 * @param projectId
	 * @param email
	 */
	public static void invitationToGuest(long selection, long projectId,
			String email) {
		long pId = projectId;
		long rId = selection;
		long uId = Long.parseLong(session.get("userId"));
		Role role = null;
		User user = null;
		Project project = null;
		String msg = "";
		String confirmation = "";
		User isMember = User.find(
				"select user from User user where user.email =?", email)
				.first();
		if (isMember != null) {
			params.flash();
			flash
					.error("The Guest you're trying to invite is already registered.");
			renderArgs.put("project", project);
			renderArgs.put("isMember", true);
			render("Projects/showProject.html");
		}
		user = User.findById(uId);
		project = Project.findById(pId);
		if (rId == 0) {
			role = Role
					.find(
							"select role from Role role where role.title='Project Member'")
					.first();
			confirmation = "Your invitation to " + email + " to join "
					+ project.name + " has been sent successfully";
			msg = "User " + user.userName + " has invited " + email
					+ " to join the project " + project.name;
		} else {
			role = Role.findById(rId);
			if (role == null) {
				params.flash();
				flash.error("This role does not exist");
				Projects.selectRoleInProject(pId, true, false);
			} else {
				confirmation = "Your invitation to " + email + " to join "
						+ project.name + " with role " + role.title
						+ " has been sent successfully";
				msg = "User " + user.userName + " has invited " + email
						+ " to join the project " + project.name + " as "
						+ role.title;
			}
		}
		params.flash();
		flash.success(confirmation);
		new Log(uId, pId, Project.class.getName(), msg, pId, "").save();
		session.put("projectId", project.getEntityId().toString());
		session.put("roleId", role.getEntityId().toString());
		sendInvitationToGuest(email, project, role);
		render("Application/index.html");
	}

	/**
	 * This method gets the user id, project id and role id from the session and
	 * adds them to the UserRoleProjects table and adds this user to the default
	 * component in this project
	 */
	public static void addUserToProject() {
		long projectId = Long.parseLong(session.get("projectId"));
		Project project = Project.findById(projectId);
		long roleId = Long.parseLong(session.get("roleId"));
		Role role = Role.findById(roleId);
		long userId = Long.parseLong(session.get("userId"));
		User user = User.findById(userId);

		User admin = getProjectAdmin(projectId);

		new UserRoleProject(true, user, role, project).save();

		List<Component> allComponents = new LinkedList<Component>();
		allComponents = Component.findAll();
		Component defaultComp = null;

		for (int i = 0; i < allComponents.size(); i++) {
			if (allComponents.get(i).name.equals("Default component")
					&& allComponents.get(i).project.equals(project)) {
				defaultComp = allComponents.get(i);
				new ComponentUser(true, user, defaultComp).save();
				break;
			}
		}

		String notify = String.format(
				"%s have accepted to join project \"%s\".", user.userName,
				project.name);

		new Notification((Long) admin.getEntityId(), "Accepted Invitation",
				notify).save();

		new Log((Long) user.getEntityId(), null, null, notify, (Long) project
				.getEntityId(), null).save();

		Registration.regStatus = false;
		renderArgs.put("user", user.userName);
		render("Application/index.html");

	}

	/**
	 * get all users in a project
	 * 
	 * @param projectID
	 *            the project id
	 * @return List of users
	 */

	public static List<User> getUsersInProject(long projectID) {

		Project P = Project.findById(projectID);

		List<User> allusers = UserRoleProject.find(
				"select u.user from UserRoleProject u where u.project=?", P)
				.fetch();
		return allusers;

	}

	/**
	 * get all developers in a project
	 * 
	 * @param projectID
	 * @return List of users
	 */

	public static List<User> getDeveloperInProject(long projectID) {

		List<User> devInP = UserRoleProject
				.find(
						"select u.user from UserRoleProject u where u.role.title='Developer'")
				.fetch();

		return devInP;

	}

	/**
	 * gets the component a user belongs to in a specific project.
	 * 
	 * @param userId
	 * @param projectId
	 * @return Component
	 */
	public static Component getUserComponent(Long userId, Long projectId) {
		Project project = Project.findById(projectId);
		User user = User.findById(userId);
		List<Long> compUserIds = ComponentUser
				.find(
						"select cu.id from ComponentUser cu where cu.user=? and cu.isMember=?",
						user, true).fetch();
		Component result = null;
		for (int i = 0; i < compUserIds.size(); i++) {
			ComponentUser compUser = ComponentUser.findById(compUserIds.get(i));
			if (compUser.component.project.equals(project)) {
				result = compUser.component;
				break;
			}
		}
		return result;

	}

	/**
	 * this is the method that is called when a user clicks on a link to request
	 * being deleted from the system then the system admin is notofied and the
	 * action is added in the log
	 */

	public static void systemDeletionRequest() {
		long userId = Long.parseLong(session.get("userId"));
		User user = User.findById(userId);
		user.hasRequestedDeletion = true;
		user.save();
		Role Admin = Role.find("byTitle", "System Admin").first();

		User user1 = UserRoleProject.find(
				"select u.user from UserRoleProject u where u.role = ?", Admin)
				.first();
		String desc = user.userName
				+ " has requested to be deleted from the system";
		Notification not = new Notification(user1.getId(), "Deletion Request",
				desc);

		not.save();
		Log log = new Log(userId, null, null, desc, null, null);
		log.save();

		String encUserId = /* Crypto.encryptAES( */user.id + "";
		String encUserName = user.firstName;/*
											 * Crypto.encryptAES( String.format(
											 * "%s %s %s", user.firstName,
											 * user.middleName, user.lastName )
											 * ;
											 */
		String link = String
				.format(
						"http://localhost:9000/projects/showRequestedProjects?userId=%s,userName=%s",
						encUserId, encUserName);

		String message = String
				.format(
						"Dear %s,\n%s has requested to leave the system .\nTo accept please click the following link: \n%s",
						user1.userName, user.userName, link);

		Mail.send("coolSoft@SMT.com", user1.email, "Request to leave system",
				message);

		flash
				.success("An email has been sent to the system admin to grant/reject your request");
		renderArgs.put("user", user.userName);
		render("Application/index.html", user.hasRequestedDeletion);
	}

	/**
	 * gets a list of users that have a specific action permission in a specific
	 * project
	 * 
	 * @param actionName
	 *            the required action
	 * @param projectId
	 *            the required project
	 * 
	 */
	public static List<User> getUsersWithPermission(String actionName,
			long projectId) {
		// get the required action
		Action a = Action.find("byName", actionName).first();
		// null validations in case of empty DB
		if (a == null)
			return null;
		// get the roles that have that action permission
		List<Role> allRoles = a.roles;
		// get the required project
		Project p = Project.findById(projectId);
		if (p == null)
			return null;
		if (allRoles == null)
			return null;
		if (allRoles.isEmpty())
			return null;
		// getting every user having a role that has the action permission
		List<User> allUsers = new LinkedList<User>();
		// outer loop to iterate over the roles
		for (int i = 0; i < allRoles.size(); i++) {
			Role r = allRoles.get(i);
			List<User> tmpUsers = UserRoleProject
					.find(
							"select distinct urp.user from UserRoleProject urp where urp.project=? and urp.role=? and urp.status=?",
							p, r, true).fetch();
			// inner loop to iterate over each user having that role
			for (int j = 0; j < tmpUsers.size(); j++) {
				User u = tmpUsers.get(j);
				// if the user has that action from a different role, then no
				// need to be repeated
				if (!allUsers.contains(u))
					allUsers.add(u);
			}
		}
		return allUsers;

	}

	/**
	 * getUserTasks
	 * 
	 * @param userId
	 * @return List of tasks
	 * 
	 *         given a userId this method returns a list of tasks assigned to
	 *         this user
	 * 
	 */
	public static List<Task> getUserTasks(long userId) {
		User user = User.findById(userId);

		List<Task> userTasks = TaskUserUser
				.find(
						"select tuu.task from TaskUserUser tuu where tuu.status = true and tuu.assignee = ?",
						user).fetch();

		return userTasks;
	}

	/**
	 * @param userId
	 * @param projectId
	 * @return List of tasks
	 * 
	 *         given a userId and a projectId , this method returns a list of
	 *         all tasks of this user in this project
	 * 
	 */
	public static List<Task> getUserTasksInProject(long userId, long projectId) {
		Project project = Project.findById(projectId);
		List<Task> projectTasks = project.getAllProjectTasks();

		List<Task> userTasks = getUserTasks(userId);

		List<Task> userProjectTasks = new LinkedList<Task>();

		for (int i = 0; i < projectTasks.size(); i++)
			for (int j = 0; j < userTasks.size(); j++)
				if (projectTasks.get(i).getEntityId().equals(
						userTasks.get(j).getEntityId()))
					userProjectTasks.add(userTasks.get(j));

		return userProjectTasks;
	}

	/**
	 * @param userId
	 * @param projectId
	 * @return List of tasks
	 * 
	 *         given a userId and a projectId , this method returns a list of
	 *         all unresolved tasks of this user in this project
	 * 
	 */
	public static List<Task> getUnresolvedTasks(long userId, long projectId) {
		List<Task> userProjectTasks = getUserTasksInProject(userId, projectId);

		List<Task> unresolvedTasks = new LinkedList<Task>();

		for (int i = 0; i < userProjectTasks.size(); i++)
			if (!userProjectTasks.get(i).status.status.equals("FIXED")
					|| !userProjectTasks.get(i).status.status
							.equals("RESOLVED")
					|| !userProjectTasks.get(i).status.status.equals("CLOSED"))
				unresolvedTasks.add(userProjectTasks.get(i));

		return unresolvedTasks;
	}

	/**
	 * @param projectId
	 * @return User
	 * 
	 *         given a projectId, this method returns the admin of this project
	 * 
	 */
	public static User getProjectAdmin(long projectId) {
		Project project = Project.findById(projectId);

		User projectAdmin = UserRoleProject
				.find(
						"select u.user from UserRoleProject u where u.role.title = 'Project Admin' and u.project = ?",
						project).first();

		return projectAdmin;
	}

	/**
	 * @param projectId
	 *            This method sends an email to the project admin saying that a
	 *            member is requesting to leave the project only if this user
	 *            doesn't have any unresolved tasks in this project
	 */
	public static void leaveProject(long projectId) {

		long userId = Long.parseLong(session.get("userId"));

		List<Task> unresolvedTasks = getUnresolvedTasks(userId, projectId);

		User user = User.findById(userId);

		Project project = Project.findById(projectId);

		String encUserId = /* Crypto.encryptAES( */user.id + "";
		String encUserName = user.firstName;/*
											 * Crypto.encryptAES( String.format(
											 * "%s %s %s", user.firstName,
											 * user.middleName, user.lastName )
											 * ;
											 */
		String encProjId = project.id + "";
		String encProjName = project.name;

		User admin = getProjectAdmin(projectId);

		if (user.equals(admin)) {
			System.out.print("YARAB");
			flash
					.error("Sorry, you are not allowed to leave this project as you are its admin");
			Projects.showProject(projectId);
		}

		else {
			if (unresolvedTasks.isEmpty()) {
				if (admin != null) {

					String link = String
							.format(
									"http://coolscrum.selfip.com/users/approveRequest?userId=%s&projId=%s&userName=%s&projName=%s",
									encUserId, encProjId, encUserName,
									encProjName);

					String message = String
							.format(
									"Dear %s,\n%s has requested to leave project \"%s\".\nTo accept please click the following link: \n%s",
									admin.userName, user.userName,
									project.name, link);

					Mail.send("coolSoft@SMT.com", admin.email,
							"Request to leave project", message);

					String notify = String.format(
							"%s has requested to leave project \"%s\".",
							user.userName, project.name);

					new Notification((Long) admin.getEntityId(),
							"Request to leave project", notify).save();

					new Log((Long) user.getEntityId(), null, null, notify,
							(Long) project.getEntityId(), null).save();

					flash
							.success("An email has been sent to the project admin to grant/reject your request");
					Projects.showProject(projectId);
				} // else
				// Projects.showProject(projectId);
			}

			else {

				flash
						.error("Sorry, you are not allowed to leave this project as you still have unresolved tasks");
				Projects.showProject(projectId);
			}
		}
	}

	/**
	 * This methods gets the user id from the session and views all the info of
	 * this user
	 */
	public static void viewProfile() {

		long userId = Long.parseLong(session.get("userId"));
		User user = User.findById(userId);

		String firstName = user.firstName;
		String middleName = "";

		if (user.middleName != null)
			middleName = user.middleName;

		String lastName = user.lastName;
		String userName = user.userName;
		String email = user.email;
		String country = user.country;
		String city = user.city;
		String address = "";

		if (user.address != null)
			address = user.address;

		String phone = "";

		if (!user.phone.equals("0"))
			phone = user.phone;

		renderArgs.put("firstName", firstName);
		renderArgs.put("middleName", middleName);
		renderArgs.put("lastName", lastName);
		renderArgs.put("userName", userName);
		renderArgs.put("email", email);
		renderArgs.put("country", country);
		renderArgs.put("city", city);
		renderArgs.put("address", address);
		renderArgs.put("phone", phone);

		render("Users/viewProfile.html");

	}

	/**
	 * @param firstName
	 * @param middleName
	 * @param lastName
	 * @param username
	 * @param password
	 * @param email
	 * @param phone
	 * @param address
	 * @param city
	 * @param country
	 * 
	 *            This methods takes all the info of a certain user, and changes
	 *            the current info in the database
	 */
	public static void editProfile(@Required String firstName,
			String middleName, @Required String lastName,
			@Required String username, @Required String password,
			@Required String email, String phone, String address, String city,
			String country) {

		long userId = Long.parseLong(session.get("userId"));
		User user = User.findById(userId);

		List<User> users = new LinkedList<User>();

		boolean unique = true;
		boolean unique2 = true;
		users = User.findAll();

		if (!username.equals(user.userName)) {
			for (int i = 0; i < users.size() && users != null; i++) {
				if (username.equals(users.get(i).userName)) {
					unique = false;
					break;
				}
			}

			if (!unique && username != null) {

				flash
						.error("This username is already in use, please choose another one");
				editPage();
				return;
			}

			else
				user.userName = username;
		}

		if (!email.equals(user.email)) {
			for (int i = 0; i < users.size() && users != null; i++) {
				if (email.equals(users.get(i).email)) {
					unique2 = false;
					break;
				}
			}

			if (!unique2) {

				flash
						.error("This email is already in use, please choose another one");
				editPage();
				return;
			}

			else
				user.email = email;
		}
		user.firstName = firstName;
		user.middleName = middleName;
		user.lastName = lastName;
		user.password = password;
		user.country = country;
		user.city = city;
		user.address = address;
		user.phone = phone;
		user.image = null;
		user.save();

		String notify = String.format("%s has edited his profile.",
				user.userName);

		new Log(userId, null, null, notify, null).save();

		viewProfile();
	}

	/**
	 * This method get the current user info from the database and fills all the
	 * text fields in the edit profile page
	 */
	public static void editPage() {
		long userId = Long.parseLong(session.get("userId"));
		User user = User.findById(userId);

		String firstName = user.firstName;
		String middleName = "";

		if (user.middleName != null)
			middleName = user.middleName;

		String lastName = user.lastName;
		String userName = user.userName;
		String password = user.password;
		String email = user.email;
		String country = user.country;
		String city = user.city;
		String address = "";

		if (user.address != null)
			address = user.address;

		String phone = "";
		if (!user.phone.equals("0"))
			phone = user.phone;

		renderArgs.put("firstName", firstName);
		renderArgs.put("middleName", middleName);
		renderArgs.put("lastName", lastName);
		renderArgs.put("userName", userName);
		renderArgs.put("password", password);
		renderArgs.put("email", email);
		renderArgs.put("country", country);
		renderArgs.put("city", city);
		renderArgs.put("address", address);
		renderArgs.put("phone", phone);

		render("Users/editProfile.html");
	}

	/**
	 * Deletes the user with userId from the project with projectId.
	 * 
	 * @param userId
	 *            the id of the user to be deleted
	 * @param projectId
	 *            the id of the project from which the user will be deleted
	 */
	public static boolean approveProjectDeletion(String userId, String projectId) {
		Long uid = Long.parseLong(userId);
		Long pid = Long.parseLong(projectId);
		// List<Task> unresolvedTasks = getUnresolvedTasks(uid, pid);
		// UserRoleProject urp;
		// if (unresolvedTasks.isEmpty()) {
		UserRoleProject urp = UserRoleProject
				.find(
						"select urp from UserRoleProject urp where urp.user.id=? and urp.project.id=?",
						uid, pid).first();
		urp.delete();
		render("main.html");
		return true;

	}

	public static void viewNotifications() {
		User thisUser = User.findById(Long.parseLong(session.get("userId")));
		List<Notification> allNotifications = Notification.find(
				"userId = ? order by date desc", (Long) thisUser.getEntityId())
				.fetch(20);
		render(allNotifications);
	}

	/**
	 * just a method to render the page requests
	 */
	public static void Requests() {
		render();
	}

	/**
	 * a method that renders all system deletion requests to the page
	 * Users/respondToSystemDeletionRequests.html
	 */
	public static void getSystemDeletionRequests() {
		List<User> requests = User
				.find(
						"select u from User u where u.hasRequestedDeletion=? and u.isDeactivated=?",
						true, false).fetch();

		render("Users/respondToSystemDeletionRequests.html", requests);
	}

	/**
	 * the method dissociates all tasks assigned to the user and deletes a
	 * project if he is his admin and de-activates his account
	 * 
	 * @param request
	 *            id of the user
	 * @param accepted
	 *            response of the system admin
	 */
	public static void respondToSystemDeletionRequests(long request,
			boolean accepted) {
		User requestPerson = User.findById(request);
		if (accepted) {
			// List<UserRoleProject> urp
			// =UserRoleProject.find("select u from UserRoleProject u where u.user=?",request).fetch();
			List<Role> u = UserRoleProject.find(
					"select u.role from UserRoleProject u where u.user=?",
					requestPerson).fetch();
			for (int i = 0; i < u.size(); i++) {
				Project project = Project
						.find(
								"select p.project from UserRoleProject p where p.user=? and p.role=? ",
								requestPerson, u.get(i)).first();
				if (u.get(i).title.equals("Project Admin")) {
					project.delete();
				}
				if (requestPerson
						.getAssignedTasks((Long) project.getEntityId()) != null) {
					List<Task> task = requestPerson
							.getAssignedTasks((Long) project.getEntityId());
					for (int j = 0; j < task.size(); j++) {
						TaskUserUser taskUserUser = TaskUserUser
								.find(
										"select tuu from TaskUserUser tuu where tuu.task=? and tuu.status=?",
										task.get(j), true).first();
						taskUserUser.assignee = null;
						taskUserUser.save();
					}

				}
			}
			requestPerson.hasRequestedDeletion = false;
			requestPerson.isDeactivated = true;
			requestPerson.save();
		} else {
			requestPerson.hasRequestedDeletion = false;
			requestPerson.save();
		}
		List<User> requests = User
				.find(
						"select u from User u where u.hasRequestedDeletion=? and u.isDeactivated=?",
						true, false).fetch();

		render(requests);
	}

	/**
	 * method that gets the roles of a user in a certain project
	 * 
	 * @param userId
	 *            id of user
	 * @param projectId
	 *            id of project
	 * @return returns the role
	 */
	public static Role getRoleInProject(long userId, long projectId) {
		User user = User.findById(userId);
		Project project = Project.findById(projectId);
		Role role = UserRoleProject
				.find(
						"select u.role from UserRoleProject u where u.project=? and u.user=?",
						project, user).first();
		return role;
	}

	public static void approveRequest() {
		render("Users/approveRequest.html");
	}

	public static void denyRequest() {
		render("main.html");
	}

	/**
	 * method to check if user is system admin
	 * 
	 * @return
	 */
	public static boolean isSystemAdmin() {
		long userId = Long.parseLong(session.get("userId"));
		User user = User.findById(userId);
		List<Role> role = UserRoleProject.find(
				"select urp.role from UserRoleProject urp where urp.user=?",
				user).fetch();
		for (int i = 0; i < role.size(); i++) {
			if (role.get(i).title.equals("System Admin"))
				return true;
		}
		return false;
	}

}